package com.rtx.edi.platform.handler;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.rtx.edi.model.api.po.PlApiMappingStructure;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class JsonConvertHandler {

    /**
     * 源JSON
     */
    private String sourceJosn;

    /**
     * JSON字段映射关系
     */
    private List<PlApiMappingStructure> structureList;

    /**
     * 全局变量
     */
    private Map<String, Map<String, Object>> globalMap;

    private JSONObject current;

//    public JsonConvertHandler(){}

    public JsonConvertHandler(String sourceJosn,List<PlApiMappingStructure> structureList,Map<String, Map<String, Object>> globalMap){
        this.sourceJosn = sourceJosn;
        this.structureList = structureList;
        this.globalMap = globalMap;
    }

    /**
     * 转化JSON
     * @return
     */
    public String convertJson() {
        if(!StringUtils.hasText(this.sourceJosn)){
            return null;
        } else if(this.sourceJosn.startsWith("[")){
            return convertJsonArray();
        }else{
            return convertJsonObject();
        }
    }

    /**
     * 转化JSONOBJECT
     * @return
     */
    private String convertJsonObject() {
        this.current = JSONArray.parseObject(this.sourceJosn);
        if(current == null){
            return null;
        }
        //根据场景ID获取报文结构并分组
        Map<Long, List<PlApiMappingStructure>> map = this.structureList.stream().collect(Collectors.groupingBy(PlApiMappingStructure::getSourceParentField));
        //如果没有配置报文映射，或没有根节点，直接返回源JSON
        if(map == null || !map.containsKey(-1L)){
            return this.sourceJosn;
        }
        return jsonFieldMapping(-1L,current,map).toJSONString();
    }

    /**
     * 转化JSONARRAY
     * @return
     */
    private String convertJsonArray() {
        JSONArray jsonArray = JSONArray.parseArray(this.sourceJosn);
        if(CollectionUtils.isEmpty(jsonArray)){
            return null;
        }
        //根据场景ID获取报文结构
        Map<Long, List<PlApiMappingStructure>> map = this.structureList.stream().collect(Collectors.groupingBy(PlApiMappingStructure::getSourceParentField));
        //如果没有配置报文映射，或没有根节点，直接返回源JSON
        if(map == null || !map.containsKey(-1L)){
            return this.sourceJosn;
        }
        JSONArray array = new JSONArray();
        for(int i = 0; i < jsonArray.size(); i++){
            this.current = jsonArray.getJSONObject(i);
            array.add(jsonFieldMapping(-1L,this.current,map));
        }
        return array.toJSONString();
    }

    /**
     * 字段对应转化
     * @param parentId
     * @param jsonObject
     * @param map
     * @return
     */
    private JSON jsonFieldMapping(long parentId, JSONObject jsonObject, Map<Long, List<PlApiMappingStructure>> map) {
        JSONObject result = new JSONObject();
        List<PlApiMappingStructure> structureList = map.get(parentId);
        for(PlApiMappingStructure s : structureList){
            //获取目标节点，如果为空则不处理
            if(!StringUtils.hasText(s.getTargetFieldName())){
                continue;
            }
            String key = s.getTargetFieldName();
            //没有对应源节点
            if(!StringUtils.hasText(s.getSourceFieldName())){
                result.put(key,getMappingValue(jsonObject,s));
            }else{
                if ("object".equals(s.getSourceFieldType())) {
                    //判断是否存在子节点，如果存在继续处理子节点，否则写入对应节点对象
                    if(map.containsKey(s.getSourceFieldCode())){
                        result.put(key,jsonFieldMapping(s.getSourceFieldCode(),jsonObject.getJSONObject(s.getSourceFieldName()),map));
                    }else{
                        result.put(key,jsonObject.getJSONObject(s.getSourceFieldName()));
                    }
                }else if ("array".equals(s.getSourceFieldType())) {
                    //判断是否存在子节点，如果存在继续处理子节点，否则写入对应节点数组
                    if(map.containsKey(s.getSourceParentField())){
                        JSONArray array = jsonObject.getJSONArray(s.getSourceFieldName());
                        JSONArray resultArray = new JSONArray();
                        for(int i = 0; i < array.size(); i++){
                            resultArray.add(jsonFieldMapping(s.getSourceFieldCode(),array.getJSONObject(i),map));
                        }
                        result.put(key,resultArray);
                    }else{
                        result.put(key,jsonObject.getJSONArray(s.getSourceFieldName()));
                    }
                }else {
                    result.put(key,jsonObject.get(s.getSourceFieldName()));
                }
            }
        }
        return result;
    }

    /**
     * 获取节点对应的值
     * @param jsonObject
     * @param structure
     * @return
     */
    private Object getMappingValue(JSONObject jsonObject,PlApiMappingStructure structure){
        Object obj = null;
        //获取源节点
        PlApiMappingStructure source = getStructureBySourceCode(structure.getMappingRequestField());
        if(structure.getSourceParentField() == source.getSourceParentField()){
            //同一层级
            if("request".equals(structure.getMappingType())){
                obj = jsonObject.get(source.getSourceFieldName());
            }else{
                obj = this.globalMap.get(source.getSourceFieldName() + jsonObject.getString(source.getSourceFieldName())).get(structure.getMappingGloableField());
            }
        }else{

        }
        return obj;
    }

    private Object findFieldValue(PlApiMappingStructure s){
        for(Map.Entry<String, Object> entry : this.current.entrySet()){
            if(entry.getKey().equals(s.getSourceFieldName())){
                return entry.getValue();
            }
        }
        return null;
    }

    /**
     * 根据源字段编号获取对应节点映射关系
     * @param code
     * @return
     */
    private PlApiMappingStructure getStructureBySourceCode(Long code){
        return this.structureList.stream().filter(s -> code == s.getSourceFieldCode()).findAny().orElse(null);
    }

    /**
     * 根据目标字段编号获取对应节点映射关系
     * @param code
     * @return
     */
    private PlApiMappingStructure getStructureByTargetCode(Long code){
        return this.structureList.stream().filter(s -> code == s.getTargetFieldCode()).findAny().orElse(null);
    }

    public String getSourceJosn() {
        return sourceJosn;
    }

    public void setSourceJosn(String sourceJosn) {
        this.sourceJosn = sourceJosn;
    }

    public List<PlApiMappingStructure> getStructureList() {
        return structureList;
    }

    public void setStructureList(List<PlApiMappingStructure> structureList) {
        this.structureList = structureList;
    }

    public Map<String, Map<String, Object>> getGlobalMap() {
        return globalMap;
    }

    public void setGlobalMap(Map<String, Map<String, Object>> globalMap) {
        this.globalMap = globalMap;
    }
}
